Amazon ECS が利用するコンテナイメージのスケジューリングロジックが変更されました
こんにちは!AWS 事業本部コンサルティング部のたかくに(@takakuni_)です。
かなり前なのですが Amazon ECS が利用するコンテナイメージのスケジューリングロジックが変更されました。
AWS Blog も公開されていますね。
今まで
今までをおさらいします。 Amazon ECS で latest
タグを使ってコンテナをデプロイしているとします。
ECR へ同じ latest
タグを付与して、新しいイメージをプッシュした場合、次のようにタグの置き代わりが発生します。
タグの起き代わりが発生したのちに、タスクのスケーリング(Desired Count の変更)が起きた場合、 ECS サービスは latest
タグが付与されている、イメージダイジェスト b のコンテナイメージを利用してスケジューリングを行う仕様でした。
この仕様の場合、サービス内で latest
タグを見ているけれども、イメージダイジェスト(コンテナイメージの中身)が異なるコンテナが混在するようなことが懸念されてきました。
これから
今回のアップデートで、スケーリング(Desired Count の変更)が行われても、古いイメージダイジェストでスケジューリングを行うようになりました。
ECS へのデプロイ時にコントロールプレーン側に、利用したイメージダイジェストを保管し、スケーリング時はコントロールプレーンに保管されたイメージダイジェストを利用する仕様になりました。
Desired Count が 3 だと仮定した場合、次の挙動になります。
- デプロイメント発生時に Desired Count の数(今回だと 3)にかかわらず、 1 つのタスク起動を試みる
- 起動したタスクのイメージタグに対応するイメージダイジェストを解決する
- 解決されたイメージダイジェストをコントロールプレーンに保管する
- コントロールプレーンに保管されたイメージダイジェストを利用して他のタスクを起動する
注意点
いくつか注意点がありますので記載します。
- 挙動 1 の 「
Desired Count の数にかかわらず
」は Desired Count が 0 のサービスには発生しない- Desired Count が 1 以上のデプロイメントにおいてイメージダイジェストの解決が発生する
- Desired Count が 0 のデプロイメントの場合は、Desired Count が 1 以上になった時点でイメージダイジェストの名前解決を試みる
- イメージダイジェストの解決が 3 回以上失敗すると、イメージダイジェストを解決せずにデプロイメントが続行される(タグベースのデプロイが行われる)
- デプロイメントサーキットブレーカーが有効になっている場合は、デプロイメントが失敗しロールバックされる
- イメージダイジェストの解決は以下のプラットフォームバージョン以上である必要がある
- Fargate Linux 1.4.0, Fargate Windows 1.0.0
- Amazon ECS Agent 1.31.0 以上
- Amazon ECS Agent 1.31.0 から 1.69.0 までは ECR にプッシュされたイメージの解決までを対応
- GuardDuty セキュリティエージェントや Service Connect プロキシなど、Amazon ECS が管理するサイドカーコンテナのダイジェストはキャプチャしない
- ECS へ新しいデプロイメントを作成することでイメージダイジェストの解決が再度実行される
やってみる
百聞は一見にしかずということで、やってみます。
ECR には latest
タグで Nginx のコンテナイメージをプッシュしている状態です。
まずはタスク定義を作成します。 latest
タグを参照するよう、コンテナイメージの指定しました。リビジョンは 2 になっていますが、タイポを書き換えただけなので、気にしないでください。
ECS サービスの作成
それでは、 ECS サービスの作成します。
注意書きの、 Desired Count 0 のデプロイメントの挙動を確認したいため、 0 の状態でサービス(デプロイメント)を作成します。
挙動の通り、 Desired Count が 0 の場合は、 ECS タスクが起動しませんでした。(まあ、そうですよね。)
ECS サービスのタスク数を変えてみます。今回は 0 から 3 に変えてみようと思います。
Started At 列を見ると挙動の通り、初めに 1 つのタスクが起動し、遅れて残りのタスクが起動する挙動に見えますね。
ECS のイベント欄からも確認できました。タスク ID 3e939b8dc1094a21b6fe91a97a89b5fc
が初めに起動し、残りの10f66aeb5ea1421387fd1cae32055b82
, c93c097fc6e548e283d3042ed4c1163f
が起動していますね。
latest タグの更新
latest
タグの更新します。更新により旧イメージ sha256:993e
から始まるイメージダイジェストのタグが外れていますね。
Desired Count の値を 3 から 5 に変更してみます。(アップデート前は latest
タグを見る挙動でした。)
latest
タグがついていた sha256:993e
で始まるイメージダイジェストで起動していますね。
イベント欄をみると、初回デプロイメントのようなイメージダイジェストの解決が行われることなく、タスクが起動していることがわかります。
新しいデプロイの強制
Force new deployment
オプションを利用して v2 へ更新してみます。タスクの起動数はそのままにしておきます。
デプロイメントが始まりました。 新しいデプロイのため、代表で 1 つのコンテナが起動していますね。
イベント欄からも同様の挙動が確認できます。
タスク定義のリビジョンを更新してみる
新しいデプロイによって、イメージの解決が行われるということは、 サービスで利用しているタスク定義のリビジョン更新も該当します。(いわゆるいつものデプロイのことです)
タスク定義のリビジョンを更新したデプロイを行ってみます。
同様の挙動が確認できますね。
以前のように同じタイミングでデプロイしたい
各デプロイメントにおいて、1 タスクが代表で起動し、イメージダイジェストの解決、解決したイメージダイジェストをもとに、残りのタスクを起動するような挙動になったため、今までよりデプロイに時間がかかるようになりました。
以前のように、タスクをなるべく同じタイミングでデプロイするには、イメージダイジェストを指定するような方法が言及されています。
To reduce potential latency associated with container image resolution in services with multiple tasks, run Amazon ECS agent version 1.83.0 or higher on EC2 container instances. To avoid potential latency altogether, specify container image digests in your task definition.
個人的に他に思いつくもので言えば、毛色は異なりますが Feature Flags(App Config)を使ったデプロイとロールアウトの分離なども考えられます。(回避したい目的がロールアウトであればですが。)
参考
まとめ
以上、「Amazon ECS が利用するコンテナイメージのスケジューリングロジックが変更されました」でした。
イメージダイジェストが保管されたことで、一貫したコンテナのスケジューリングは可能になりましたが、latest
タグを使っていい理由にはなりません。本番相当での latest
タグの利用は変わらず非推奨ですのでご注意ください。
コンテナイメージはコンテナレジストリに保存されます。レジストリ内の各イメージはタグによって識別されます。latest というタグがあります。このタグは、git リポジトリの HEAD と同様に、アプリケーションコンテナイメージの最新バージョンに対するポインターとして機能します。latest タグはテストのみに使用することが推奨されます。ベストプラクティスとして、ビルドごとにコンテナイメージに一意のタグを付けます。イメージの構築に使用された git コミットの git SHA を使用してイメージにタグ付けすることをお勧めします。
コミットごとにコンテナイメージを構築する必要はありません。ただし、特定のコードコミットを本番環境にリリースするたびに、新しいコンテナイメージを構築することをお勧めします。また、イメージに対して、イメージ内のコードの git commit に対応するタグを付けることをお勧めします。イメージに git commit のタグを付けた場合、イメージが実行しているコードのバージョンをより迅速に見つけることができます。
以上、AWS 事業本部コンサルティング部のたかくに(@takakuni_)でした!